package com.future.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.future.allUtils.constants.RedisCacheConstants;
import com.future.allUtils.utils.CacheClient;
import com.future.allUtils.utils.SecurityUtils;
import com.future.domain.*;
import com.future.domain.DTO.ArticleDTO;
import com.future.domain.vo.ArticleTagVO;
import com.future.domain.vo.CheckIsLikeVO;
import com.future.mapper.*;
import com.future.service.ArticleService;
import com.future.service.TagService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private TagService tagService;
    @Autowired
    private ArticleTagMapper articleTagMapper;
    @Autowired
    private CacheClient cacheClient;
    @Autowired
    private  MediaResourceMapper mediaResourceMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LikeMapper likeMapper;

    @Override
    @Transactional
    public Result publishArticle(ArticleDTO articleDTO) {
        // 1. 检查用户登录状态
        try {
            SecurityUtils.getCurrentUser();
        } catch (RuntimeException e) {
            return Result.fail("请先登录");
        }
        User currentUser = SecurityUtils.getCurrentUser().getUser();
        if (currentUser.getStatus()==0){
            return Result.fail("用户已被禁用");
        }

        // 2. 手动校验参数（保持不变）
        if (StringUtils.isEmpty(articleDTO.getTitle()) || articleDTO.getTitle().length() > 100) {
            return Result.fail("标题不能为空且不超过100字");
        }
        if (StringUtils.isEmpty(articleDTO.getContent()) || articleDTO.getContent().length() > 5000) {
            return Result.fail("内容不能为空且不超过5000字");
        }
        if (articleDTO.getCategoryId() == null) {
            return Result.fail("文章分类ID不能为空");
        }
        if (StringUtils.isNotEmpty(articleDTO.getImageUrl())) {
            if (articleDTO.getImageUrl().length() > 500) {
                return Result.fail("图片URL长度不超过500字符");
            }
            // 简单校验URL格式
            String urlRegex = "^(https?|ftp)://.*$";
            if (!articleDTO.getImageUrl().matches(urlRegex)) {
                return Result.fail("图片URL格式不合法");
            }
        }
        // 3. 处理标签逻辑
        List<String> tagNames = articleDTO.getTagNames();
        List<Long> tagIds = new ArrayList<>();

        if (tagNames != null) {
            List<String> validTags = tagNames.stream()
                    .filter(tag -> tag != null && !tag.trim().isEmpty()) // 过滤null和空白字符串
                    .collect(Collectors.toList());

            if (!validTags.isEmpty()) {
                // 2. 校验有效标签数量不超过3个
                if (validTags.size() > 3) {
                    return Result.fail("最多只能添加3个标签");
                }

                // 3. 查询有效标签对应的ID
                tagIds = tagService.selectTagIdsByNames(validTags);

                // 4. 校验所有有效标签必须存在（查询到的ID数量需与有效标签数量一致）
                if (tagIds.size() != validTags.size()) {
                    return Result.fail("存在不存在的标签，请检查标签名称");
                }
            }
        }

        // 3. 转换为实体类并补全字段
        Article article = new Article();
        BeanUtils.copyProperties(articleDTO, article);

        // 4. 设置时间字段（修正字段名）
        article.setCreatedAt(LocalDateTime.now());
        article.setUpdatedAt(LocalDateTime.now());

        Long authorId = SecurityUtils.getCurrentUserId();  // 获取当前用户ID
        article.setAuthorId(authorId);  // 补充作者ID

        List<Role> userRoles = roleMapper.selectUserRolesByUserId(authorId);
        if (userRoles == null || userRoles.isEmpty()) {
            return Result.fail("用户角色不存在");
        }

        String authorRole = userRoles.get(0).getRoleName();
        article.setAuthorRole(authorRole);
        article.setViews(0L);          // views 初始为0
        article.setIsApproved(0);     // 未审核状态（Integer类型）
        article.setLikeCount(0L);

// 6. 保存文章（异常捕获）
        try {
            articleMapper.insert(article);
            List<ArticleTagVO> articleTagList = tagIds.stream()
                    .map(tagId -> {
                        ArticleTagVO articleTag = new ArticleTagVO();
                        articleTag.setArticleId(article.getId());  // 设置文章ID
                        articleTag.setTagId(tagId);                // 设置标签ID
                        return articleTag;
                    })
                    .collect(Collectors.toList());

            // 批量插入（替代原循环单条插入）
            if (!articleTagList.isEmpty()) {
                articleTagMapper.batchInsertArticleTags(articleTagList);
            }

            return Result.ok("提交成功待审核");
        } catch (Exception e) {
            log.error("文章保存失败", e);  // 打印详细错误日志
            return Result.fail("服务器内部错误");
        }
    }



    /**
     * 文章审核接口实现
     * 更新文章的审核状态（isApproved），并记录审核时间和审核人
     */
    @Override
    public Result auditArticle(Long articleId, Integer isApproved) {
        // 1. 校验审核状态参数合法性
        if (isApproved == null || (isApproved != 0 && isApproved != 1)) {
            return Result.fail("审核状态无效，必须是0（未通过）或1（通过）");
        }

        // 2. 查询文章是否存在
        Article article = articleMapper.selectById(articleId);
        if (article == null) {
            return Result.fail("文章不存在或已被删除");
        }

        // 3. 更新数据库
        article.setIsApproved(isApproved);
        article.setUpdatedAt(LocalDateTime.now());
        int updateRows = articleMapper.updateById(article);

        if (updateRows > 0) {
            // ========== 关键：缓存失效逻辑 ==========
            Long categoryId = article.getCategoryId();
            if (categoryId != null) {
                // ① 失效「分类ID」关联的所有分页缓存（通配符匹配）
                String categoryIdPattern = "article:categoryId:" + categoryId + ":page:*:size:*";
                cacheClient.deleteByPattern(categoryIdPattern);

                // ② 失效「分类名称」关联的所有分页缓存（先查分类名称）
                Category category = categoryMapper.selectById(categoryId);
                if (category != null) {
                    String categoryNamePattern = "article:categoryName:" + category.getName() + ":page:*:size:*";
                    cacheClient.deleteByPattern(categoryNamePattern);
                }
            }

            // ③ 失效「已审核文章」的所有分页缓存（通配符匹配）
            String approvedPattern = "article:approved:page:*:size:*";
            cacheClient.deleteByPattern(approvedPattern);
            // 根据审核结果返回不同提示信息
            if (isApproved == 1) {
                return Result.ok("审核通过");
            } else {
                return Result.ok("审核不通过，请修改内容后重新提交");
            }
        } else {
            return Result.fail("审核失败，请重试");
        }
    }
    @Override
    public Result getApprovedArticles(IPage<Article> page) {
        // 1. 构建缓存key（包含分页参数，确保唯一性）
        long pageNum = page.getCurrent(); // 当前页码
        long pageSize = page.getSize();   // 每页条数
        String cacheKey = "article:approved:page:" + pageNum + ":size:" + pageSize;

        // 2. 查询缓存
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult;
        }

        // 3. 缓存未命中：执行数据库查询逻辑
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getIsApproved, 1)  // 审核通过
                .orderByDesc(Article::getCreatedAt);  // 按创建时间倒序
        IPage<Article> resultPage = articleMapper.selectPage(page, queryWrapper);

        List<Article> articles = resultPage.getRecords();
        if (!articles.isEmpty()) {
            List<Long> articleIds = articles.stream()
                    .map(Article::getId)
                    .collect(Collectors.toList());

            // 批量查询文章-标签关联
            List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);

            // 构建标签ID映射
            Map<Long, List<Long>> articleTagMap = new HashMap<>();
            for (ArticleTagVO vo : articleTagVOs) {
                Long tagId = vo.getTagId();
                if (tagId != null) {
                    articleTagMap.computeIfAbsent(vo.getArticleId(), k -> new ArrayList<>())
                            .add(tagId);
                }
            }

            // 为文章设置标签ID列表
            for (Article article : articles) {
                List<Long> tagIds = articleTagMap.getOrDefault(article.getId(), Collections.emptyList());
                article.setTagIds(tagIds);
            }
            List<Long> authorIds = articles.stream()
                    .map(Article::getAuthorId)
                    .distinct() // 去重作者ID，减少查询次数
                    .collect(Collectors.toList());

            if (!authorIds.isEmpty()) {
                // 批量查询作者信息
                List<User> authors = userMapper.selectBatchIds(authorIds);
                // 构建作者ID到用户名的映射
                Map<Long, String> authorNameMap = authors.stream()
                        .collect(Collectors.toMap(User::getId, User::getUsername, (existing, replacement) -> existing));

                // 为每个文章设置作者名称
                for (Article article : articles) {
                    String authorName = authorNameMap.getOrDefault(article.getAuthorId(), "未知作者");
                    article.setAuthorName(authorName);
                }

            }
        }

        // 4. 结果存入Redis（设置30分钟过期，避免数据长期过时）
        Result result = Result.ok(resultPage);
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES); // 逻辑过期（参考工程现有用法）

        // 5. 返回结果
        return result;
    }
    @Override
    public Result getAuditArticles(IPage<Article> page) {
        // 1. 构建缓存key（包含分页参数，确保唯一性）
        long pageNum = page.getCurrent(); // 当前页码
        long pageSize = page.getSize();   // 每页条数
        String cacheKey = "article:approved:page:" + pageNum + ":size:" + pageSize;

        // 2. 查询缓存
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult;
        }

        // 3. 缓存未命中：执行数据库查询逻辑
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getIsApproved, 0) // 未审核
                .orderByDesc(Article::getCreatedAt);  // 按创建时间倒序
        IPage<Article> resultPage = articleMapper.selectPage(page, queryWrapper);

        List<Article> articles = resultPage.getRecords();
        if (!articles.isEmpty()) {
            List<Long> articleIds = articles.stream()
                    .map(Article::getId)
                    .collect(Collectors.toList());

            // 批量查询文章-标签关联
            List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);

            // 构建标签ID映射
            Map<Long, List<Long>> articleTagMap = new HashMap<>();
            for (ArticleTagVO vo : articleTagVOs) {
                Long tagId = vo.getTagId();
                if (tagId != null) {
                    articleTagMap.computeIfAbsent(vo.getArticleId(), k -> new ArrayList<>())
                            .add(tagId);
                }
            }

            // 为文章设置标签ID列表
            for (Article article : articles) {
                List<Long> tagIds = articleTagMap.getOrDefault(article.getId(), Collections.emptyList());
                article.setTagIds(tagIds);
            }
            List<Long> authorIds = articles.stream()
                    .map(Article::getAuthorId)
                    .distinct() // 去重作者ID，减少查询次数
                    .collect(Collectors.toList());

            if (!authorIds.isEmpty()) {
                // 批量查询作者信息
                List<User> authors = userMapper.selectBatchIds(authorIds);
                // 构建作者ID到用户名的映射
                Map<Long, String> authorNameMap = authors.stream()
                        .collect(Collectors.toMap(User::getId, User::getUsername, (existing, replacement) -> existing));

                // 为每个文章设置作者名称
                for (Article article : articles) {
                    String authorName = authorNameMap.getOrDefault(article.getAuthorId(), "未知作者");
                    article.setAuthorName(authorName);
                }
            }
        }

        // 4. 结果存入Redis（设置30分钟过期，避免数据长期过时）
        Result result = Result.ok(resultPage);
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES); // 逻辑过期（参考工程现有用法）

        // 5. 返回结果
        return result;
    }
    @Override
    public Result getArticlesByCategoryName(IPage<Article> page, String categoryName) {
        // 校验分类名称是否有效
        if (categoryName == null || categoryName.isEmpty()) {
            return Result.fail("分类名称无效，请提供有效的分类名称");
        }

        // 构建缓存key（包含分类名称和分页参数，确保唯一性）
        long pageNum = page.getCurrent();
        long pageSize = page.getSize();
        String cacheKey = "article:categoryName:" + categoryName + ":page:" + pageNum + ":size:" + pageSize;

        // 查询缓存：复用 queryWithLogicalExpire 方法
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult;
        }

        // 查询分类ID
        Category category = categoryMapper.selectOne(new LambdaQueryWrapper<Category>().eq(Category::getName, categoryName));
        if (category == null) {
            return Result.fail("分类不存在");
        }
        Integer categoryId = category.getId();

        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        // 查询指定分类下已审核通过的文章
        queryWrapper.eq(Article::getCategoryId, categoryId)
                .eq(Article::getIsApproved, 1)  // 只查询审核通过的
                .orderByDesc(Article::getCreatedAt);  // 按创建时间倒序

        // 执行分页查询
        IPage<Article> resultPage = articleMapper.selectPage(page, queryWrapper);

        // 处理文章标签ID
        List<Article> articles = resultPage.getRecords();
        if (!articles.isEmpty()) {
            List<Long> articleIds = articles.stream()
                    .map(Article::getId)
                    .collect(Collectors.toList());

            // 批量查询文章-标签关联
            List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);

            // 构建标签ID映射
            Map<Long, List<Long>> articleTagMap = new HashMap<>();
            for (ArticleTagVO vo : articleTagVOs) {
                Long tagId = vo.getTagId();
                if (tagId != null) {
                    articleTagMap.computeIfAbsent(vo.getArticleId(), k -> new ArrayList<>())
                            .add(tagId);
                }
            }

            // 为文章设置标签ID列表
            for (Article article : articles) {
                List<Long> tagIds = articleTagMap.getOrDefault(article.getId(), Collections.emptyList());
                article.setTagIds(tagIds);
            }
            List<Long> authorIds = articles.stream()
                    .map(Article::getAuthorId)
                    .distinct()
                    .collect(Collectors.toList());

            if (!authorIds.isEmpty()) {
                List<User> authors = userMapper.selectBatchIds(authorIds);
                Map<Long, String> authorNameMap = authors.stream()
                        .collect(Collectors.toMap(User::getId, User::getUsername, (existing, replacement) -> existing));

                for (Article article : articles) {
                    article.setAuthorName(authorNameMap.getOrDefault(article.getAuthorId(), "未知作者"));
                }
            }
        }

        // 结果存入Redis（设置30分钟逻辑过期）
        Result result = Result.ok(resultPage);
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        // 返回结果
        return result;
    }
    @Override
    public Result getArticlesByCategoryId(IPage<Article> page, Long categoryId) {
        // 校验分类ID是否有效
        if (categoryId == null || categoryId <= 0) {
            return Result.fail("分类ID无效，请提供有效的分类ID");
        }

        // 构建缓存key（包含分类ID和分页参数，确保唯一性）
        long pageNum = page.getCurrent();
        long pageSize = page.getSize();
        String cacheKey = "article:categoryId:" + categoryId + ":page:" + pageNum + ":size:" + pageSize;

        // 查询缓存：复用 queryWithLogicalExpire 方法
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult;
        }

        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        // 查询指定分类下已审核通过的文章
        queryWrapper.eq(Article::getCategoryId, categoryId)
                .eq(Article::getIsApproved, 1)  // 只查询审核通过的
                .orderByDesc(Article::getCreatedAt);  // 按创建时间倒序

        // 执行分页查询
        IPage<Article> resultPage = articleMapper.selectPage(page, queryWrapper);

        // 处理文章标签ID（复用 getApprovedArticles 的标签处理逻辑）
        List<Article> articles = resultPage.getRecords();
        if (!articles.isEmpty()) {
            List<Long> articleIds = articles.stream()
                    .map(Article::getId)
                    .collect(Collectors.toList());

            // 批量查询文章-标签关联
            List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);

            // 构建标签ID映射
            Map<Long, List<Long>> articleTagMap = new HashMap<>();
            for (ArticleTagVO vo : articleTagVOs) {
                Long tagId = vo.getTagId();
                if (tagId != null) {
                    articleTagMap.computeIfAbsent(vo.getArticleId(), k -> new ArrayList<>())
                            .add(tagId);
                }
            }

            // 为文章设置标签ID列表
            for (Article article : articles) {
                List<Long> tagIds = articleTagMap.getOrDefault(article.getId(), Collections.emptyList());
                article.setTagIds(tagIds);
            }
            List<Long> authorIds = articles.stream()
                    .map(Article::getAuthorId)
                    .distinct()
                    .collect(Collectors.toList());

            if (!authorIds.isEmpty()) {
                List<User> authors = userMapper.selectBatchIds(authorIds);
                Map<Long, String> authorNameMap = authors.stream()
                        .collect(Collectors.toMap(User::getId, User::getUsername, (existing, replacement) -> existing));

                for (Article article : articles) {
                    article.setAuthorName(authorNameMap.getOrDefault(article.getAuthorId(), "未知作者"));
                }
            }
        }

        // 结果存入Redis（设置30分钟逻辑过期）
        Result result = Result.ok(resultPage);
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        // 返回结果
        return result;
    }

    @Override
    public Result getArticleLikeCount(Long articleId) {
        // 1. 校验文章ID有效性
        if (articleId == null || articleId <= 0) {
            return Result.fail("文章ID无效，请提供有效的文章ID");
        }

        // 2. 调用缓存穿透解决方案的通用方法（优化缓存键和时效）
        Long likeCount = cacheClient.queryWithPassThrough(
                RedisCacheConstants.COUNT_LIKE_ARTICLE_PREFIX,
                articleId,
                Long.class,
                (id) -> {
                    Article article = articleMapper.selectById(id);  // 仅缓存未命中时执行
                    if (article == null) {
                        return null;  // 触发缓存穿透保护（缓存空值）
                    }
                    return article.getLikeCount();
                },
                RedisCacheConstants.CACHE_NORMAL_TTL,  // 工程标准缓存时效（30分钟）
                TimeUnit.SECONDS
        );

        // 3. 处理查询结果
        if (likeCount == null) {
            // 缓存穿透保护：已缓存空值，说明文章不存在
            return Result.fail("文章不存在");
        }
        return Result.ok(likeCount);
    }

    @Override
    public Result getArticleByAuthorId(Long authorId, Integer pageNum, Integer pageSize) {
        // 1. 校验参数有效性
        if (authorId == null || authorId <= 0) {
            return Result.fail("作者ID无效，请提供有效的作者ID");
        }
        // 设置分页默认值（参考其他分页方法）
        pageNum = pageNum == null ? 1 : pageNum;
        pageSize = pageSize == null ? 10 : pageSize;

        try {
            // 2. 创建分页对象
            Page<Article> page = new Page<>(pageNum, pageSize);

            // 3. 构建查询条件：按作者ID筛选，按创建时间倒序
            LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Article::getAuthorId, authorId)
                    .orderByDesc(Article::getCreatedAt);  // 按创建时间倒序

            // 4. 执行分页查询
            IPage<Article> resultPage = articleMapper.selectPage(page, queryWrapper);
            List<Article> articles = resultPage.getRecords();

            // 5. 处理文章标签ID（复用 getApprovedArticles 的标签处理逻辑）
            if (!articles.isEmpty()) {
                List<Long> articleIds = articles.stream()
                        .map(Article::getId)
                        .collect(Collectors.toList());

                // 批量查询文章-标签关联
                List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);

                // 构建标签ID映射
                Map<Long, List<Long>> articleTagMap = new HashMap<>();
                for (ArticleTagVO vo : articleTagVOs) {
                    Long tagId = vo.getTagId();
                    if (tagId != null) {
                        articleTagMap.computeIfAbsent(vo.getArticleId(), k -> new ArrayList<>())
                                .add(tagId);
                    }
                }

                // 为文章设置标签ID列表
                for (Article article : articles) {
                    List<Long> tagIds = articleTagMap.getOrDefault(article.getId(), Collections.emptyList());
                    article.setTagIds(tagIds);
                    article.setAuthorIdStr(String.valueOf(article.getAuthorId()));
                }
                List<Long> authorIds = articles.stream()
                        .map(Article::getAuthorId)
                        .distinct()
                        .collect(Collectors.toList());

                if (!authorIds.isEmpty()) {
                    List<User> authors = userMapper.selectBatchIds(authorIds);
                    Map<Long, String> authorNameMap = authors.stream()
                            .collect(Collectors.toMap(User::getId, User::getUsername, (existing, replacement) -> existing));

                    for (Article article : articles) {
                        article.setAuthorName(authorNameMap.getOrDefault(article.getAuthorId(), "未知作者"));
                    }
                }
            }

            return Result.ok(resultPage);
        } catch (Exception e) {
            log.error("查询作者文章失败", e);
            return Result.fail("查询文章失败");
        }
    }

    @Override
    public Result getSelfArticle(Integer pageNum, Integer pageSize) {
        try {
            Long currentUserId = SecurityUtils.getCurrentUserId();
            pageNum = pageNum == null ? 1 : pageNum;
            pageSize = pageSize == null ? 10 : pageSize;
            return getArticleByAuthorId(currentUserId, pageNum, pageSize);
        } catch (Exception e) {
            return  Result.fail("请先登录");
        }

    }

    @Override
    @Transactional
    public Result deleteSelfArticle(Long articleId) {
        // 1. 校验文章ID有效性
        if (articleId == null || articleId <= 0) {
            return Result.fail("文章ID无效，请提供有效的文章ID");
        }
        // 2. 校验文章是否存在
        Article article = articleMapper.selectById(articleId);
        if (article == null) {
            return Result.fail("文章不存在");
        }
        // 3. 校验文章是否为当前用户的
        // 修改开始：添加未登录处理
        Long currentUserId = null;
        try {
            currentUserId = SecurityUtils.getCurrentUserId();
        } catch (RuntimeException e) {
            return Result.fail("请先登录");
        }
        // 修改结束
        if (!currentUserId.equals(article.getAuthorId())) {
            return Result.fail("您没有权限删除他人的文章");
        }
        // 4. 删除文章
        int rows = articleMapper.deleteById(articleId);
        if (rows <= 0) {
            return Result.fail("删除文章失败");
        }
        return Result.ok("删除文章成功");
    }

    @Override
    @Transactional
    public Result deleteArticle(Long articleId) {
        // 1. 校验文章ID有效性
        if (articleId == null || articleId <= 0) {
            return Result.fail("文章ID无效，请提供有效的文章ID");
        }
        // 2. 校验文章是否存在
        Article article = articleMapper.selectById(articleId);
        if (article == null) {
            return Result.fail("文章不存在");
        }
        // 3. 删除文章
        int rows = articleMapper.deleteById(articleId);
        if (rows <= 0) {
            return Result.fail("删除文章失败");
        }
        return Result.ok("删除文章成功");
    }

    @Override
    public Result getArticleByArticleId(Long articleId) {
        // 1. 参数校验
        if (articleId == null || articleId <= 0) {
            return Result.fail("文章ID无效");
        }

        final String keyPrefix = "article:detail:";
        final String cacheKey = keyPrefix + articleId;

        try {
            // 2. 独立更新浏览量（每次访问必执行，与缓存逻辑解耦）
            int updateRows = articleMapper.incrementViews(articleId);
            if (updateRows <= 0) {
                // 更新失败时检查文章是否存在（避免缓存穿透）
                Article article = articleMapper.selectById(articleId);
                if (article == null) {
                    return Result.fail("文章不存在");
                }
            }


            // 3. 定义缓存未命中时的数据库查询逻辑（仅缓存失效时执行）
            Function<Long, Result> dbQuery = id -> {
                // 查询文章基本信息
                Article article = articleMapper.selectById(id);
                if (article == null) {
                    return Result.fail("文章不存在");
                }

                // 设置标签ID列表
                List<Long> tagIds = articleTagMapper.selectArticleTagIdsByArticleIds(Collections.singletonList(id))
                        .stream()
                        .map(ArticleTagVO::getTagId)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());
                article.setTagIds(tagIds);

                // 设置作者信息
                User author = userMapper.selectById(article.getAuthorId());
                article.setAuthorName(author != null ? author.getUsername() : "未知作者");
                article.setAuthorIdStr(String.valueOf(article.getAuthorId()));

                // 设置点赞/收藏状态（未登录用户默认false）
                Long currentUserId = null;
                try {
                    currentUserId = SecurityUtils.getCurrentUserId();
                } catch (RuntimeException e) {
                    article.setIsLiked(false);
                    article.setIsCollected(false);
                }
                if (currentUserId != null) {
                    article.setIsLiked(likeMapper.selectLikeOrNotByArticleId(id, currentUserId) > 0);
                    article.setIsCollected(likeMapper.selectCollectOrNotByArticleId(id, currentUserId) > 0);
                }

                return Result.ok(article);
            };

            // 4. 缓存优先查询（先查缓存，未命中才执行dbQuery）
            Result result = cacheClient.queryWithLogicalExpire(
                    keyPrefix,
                    articleId,
                    Result.class,
                    dbQuery,  // 缓存未命中时执行的数据库查询逻辑
                    30L,      // 逻辑过期时间（30分钟）
                    TimeUnit.MINUTES
            );

            if (result == null) {
                // 缓存未命中时，手动查询数据库并更新缓存
                result = dbQuery.apply(articleId);
                if (result != null && result.getData() != null) {
                    // 将数据库查询结果存入缓存（设置逻辑过期）
                    cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);
                }
            }

            return result != null ? result : Result.fail("文章不存在");
        } catch (Exception e) {
            log.error("查询文章详情失败", e);
            return Result.fail("系统错误");
        }
    }
    @Override
    public Result getArticlesByAuthorIdAndTitle(IPage<Article> page, Long authorId, String title) {
        // 1. 校验标题参数
        if (StringUtils.isEmpty(title)) {
            // 修改：使用page对象中的分页参数，而非硬编码1和10
            return getArticleByAuthorId(authorId, (int) page.getCurrent(), (int) page.getSize());
        }
        // 校验作者ID
        if (authorId == null || authorId <= 0) {
            return Result.fail("作者ID无效，请提供有效的作者ID");
        }

        // 2. 构建缓存Key（包含作者ID、标题关键词、分页参数，确保唯一性）
        long pageNum = page.getCurrent();
        long pageSize = page.getSize();
        String cacheKey = "article:author:" + authorId + ":title:" + title + ":page:" + pageNum + ":size:" + pageSize;

        // 3. 先查缓存（复用项目现有缓存逻辑，如queryWithLogicalExpire）
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES  // 30分钟逻辑过期
        );
        if (cachedResult != null) {
            return cachedResult;  // 缓存命中，直接返回
        }

        // 4. 缓存未命中，执行数据库分页查询
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getAuthorId, authorId)  // 按作者ID筛选
                .like(Article::getTitle, title)      // 标题模糊匹配
                .orderByDesc(Article::getCreatedAt); // 按创建时间倒序

        IPage<Article> resultPage = articleMapper.selectPage(page, queryWrapper);
        List<Article> articles = resultPage.getRecords();

        // 5. 处理文章标签ID（复用现有标签关联逻辑）
        if (!articles.isEmpty()) {
            List<Long> articleIds = articles.stream()
                    .map(Article::getId)
                    .collect(Collectors.toList());

            List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);
            Map<Long, List<Long>> articleTagMap = new HashMap<>();
            for (ArticleTagVO vo : articleTagVOs) {
                Long tagId = vo.getTagId();
                if (tagId != null) {
                    articleTagMap.computeIfAbsent(vo.getArticleId(), k -> new ArrayList<>())
                            .add(tagId);
                }
            }

            for (Article article : articles) {
                article.setTagIds(articleTagMap.getOrDefault(article.getId(), Collections.emptyList()));
            }
            List<Long> authorIds = articles.stream()
                    .map(Article::getAuthorId)
                    .distinct()
                    .collect(Collectors.toList());

            if (!authorIds.isEmpty()) {
                List<User> authors = userMapper.selectBatchIds(authorIds);
                Map<Long, String> authorNameMap = authors.stream()
                        .collect(Collectors.toMap(User::getId, User::getUsername, (existing, replacement) -> existing));

                for (Article article : articles) {
                    article.setAuthorName(authorNameMap.getOrDefault(article.getAuthorId(), "未知作者"));
                }
            }
        }

        // 6. 结果存入缓存（设置逻辑过期，避免缓存与数据库数据长期不一致）
        Result result = Result.ok(resultPage);
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        return result;
    }
    @Override
    public Result getArticlesByAuthorAndTitle(IPage<Article> page,String title) {

        // 修改开始：添加未登录处理
        Long authorId = null;
        try {
            authorId = SecurityUtils.getCurrentUserId();
        } catch (RuntimeException e) {
            return Result.fail("请先登录");
        }
        // 校验标题参数
        if (StringUtils.isEmpty(title)) {
            // 修改：使用page对象中的分页参数，而非硬编码1和10
            return getArticleByAuthorId(authorId, (int) page.getCurrent(), (int) page.getSize());
        }
        // 修改结束
        return getArticlesByAuthorIdAndTitle(page,authorId,title);
    }

    private Result dbFallback(Long articleId) {
        Article article = articleMapper.selectById(articleId);
        if (article == null) {
            return null;
        }
        List<Long> articleIds = Collections.singletonList(articleId);
        List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);
        List<Long> tagIds = articleTagVOs.stream()
                .map(ArticleTagVO::getTagId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        article.setTagIds(tagIds);
        User author = userMapper.selectById(article.getAuthorId());
        String authorName = author != null ? author.getUsername() : "未知作者";
        article.setAuthorName(authorName);
        return Result.ok(article);
    }
    @Override
    public Result getArticlesByTitle(IPage<Article> page, String title) {
        // 校验标题参数
        if (StringUtils.isEmpty(title)) {
            return Result.fail("标题不能为空，请输入查询关键词");
        }

        // 构建缓存key（包含标题关键词和分页参数，确保唯一性）
        long pageNum = page.getCurrent();
        long pageSize = page.getSize();
        String cacheKey = "article:title:" + title + ":page:" + pageNum + ":size:" + pageSize;

        // 查询缓存：复用 queryWithLogicalExpire 方法
        Result cachedResult = cacheClient.queryWithLogicalExpire(
                "", cacheKey, Result.class,
                id -> null, 30L, TimeUnit.MINUTES
        );
        if (cachedResult != null) {
            return cachedResult;
        }

        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        // 模糊查询标题（包含关键词），且只查询已审核通过的文章
        queryWrapper.like(StringUtils.isNotBlank(title), Article::getTitle, title)
                .eq(Article::getIsApproved, 1)  // 只查询审核通过的
                .orderByDesc(Article::getCreatedAt);  // 按创建时间倒序

        // 执行分页查询
        IPage<Article> resultPage = articleMapper.selectPage(page, queryWrapper);

        // 处理文章标签ID（复用 getApprovedArticles 的标签处理逻辑）
        List<Article> articles = resultPage.getRecords();
        if (!articles.isEmpty()) {
            List<Long> articleIds = articles.stream()
                    .map(Article::getId)
                    .collect(Collectors.toList());

            // 批量查询文章-标签关联
            List<ArticleTagVO> articleTagVOs = articleTagMapper.selectArticleTagIdsByArticleIds(articleIds);

            // 构建标签ID映射
            Map<Long, List<Long>> articleTagMap = new HashMap<>();
            for (ArticleTagVO vo : articleTagVOs) {
                Long tagId = vo.getTagId();
                if (tagId != null) {
                    articleTagMap.computeIfAbsent(vo.getArticleId(), k -> new ArrayList<>())
                            .add(tagId);
                }
            }

            // 为文章设置标签ID列表
            for (Article article : articles) {
                List<Long> tagIds = articleTagMap.getOrDefault(article.getId(), Collections.emptyList());
                article.setTagIds(tagIds);
            }
            List<Long> authorIds = articles.stream()
                    .map(Article::getAuthorId)
                    .distinct()
                    .collect(Collectors.toList());

            if (!authorIds.isEmpty()) {
                List<User> authors = userMapper.selectBatchIds(authorIds);
                Map<Long, String> authorNameMap = authors.stream()
                        .collect(Collectors.toMap(User::getId, User::getUsername, (existing, replacement) -> existing));

                for (Article article : articles) {
                    article.setAuthorName(authorNameMap.getOrDefault(article.getAuthorId(), "未知作者"));
                }
            }
        }

        // 结果存入Redis（设置30分钟逻辑过期）
        Result result = Result.ok(resultPage);
        cacheClient.setWithLogicalExpire(cacheKey, result, 30L, TimeUnit.MINUTES);

        // 返回结果
        return result;
    }

    @Override
    public Result checkArticle(Long articleId) {
        if (articleId == null){
            return Result.fail("文章ID不能为空");
        }
        Article article = articleMapper.selectById(articleId);
        if (article == null){
            return Result.fail("文章不存在");
        }
        CheckIsLikeVO checkIsLikeVO = new CheckIsLikeVO();
        // 修改开始：直接从SecurityContext获取认证信息并处理类型转换
        Long currentUserId = null;
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication == null) {
                throw new RuntimeException("未登录");
            }
            Object principal = authentication.getPrincipal();
            if (principal instanceof LoginUserDetails) {
                // 正常情况：主体是LoginUserDetails对象
                currentUserId = ((LoginUserDetails) principal).getUser().getId();
            } else if (principal instanceof String) {
                // 兼容处理：主体是用户ID字符串（如某些认证场景）
                currentUserId = Long.parseLong((String) principal);
            } else {
                throw new RuntimeException("不支持的认证主体类型");
            }
        } catch (RuntimeException e) {
            // 未登录或认证信息异常时，默认返回未点赞/未收藏状态
            checkIsLikeVO.setLikeCount(article.getLikeCount());
            checkIsLikeVO.setLiked(false);
            checkIsLikeVO.setCollectionCount(article.getCollectionCount());
            checkIsLikeVO.setCollected(false);
            return Result.ok(checkIsLikeVO);
        }
        // 修改结束

        int isLike = likeMapper.selectLikeOrNotByArticleId(articleId, currentUserId);
        checkIsLikeVO.setLikeCount(article.getLikeCount());
        checkIsLikeVO.setLiked(isLike > 0);
        int isCollected = likeMapper.selectCollectOrNotByArticleId(articleId, currentUserId);
        checkIsLikeVO.setCollectionCount(article.getCollectionCount());
        checkIsLikeVO.setCollected(isCollected > 0);
        return Result.ok(checkIsLikeVO);
    }
}